﻿using System.Collections.Generic;
using System.IO;
using System.Text;
using CalcSharp.Core;
using CalcSharp.Core.Containers;
using dnAnalytics.Statistics.Distributions;

namespace CalcSharp
{
    enum StatSample
    {
        Bernoulli,
        Beta,
        Binomial,
        ContinuousUniform,
        Delta,
        Dirichlet,
        DiscreteUniform,
        Exponential,
        Gamma,
        Geometric,
        InverseGamma,
        Laplace,
        NegativeBinomial,
        Normal,
        Permutation,
        Poission
    }

    class SetFuncts
    {
        private SetFuncts() { }
        public static ASet makeSet(string input)
        {
            List<double> db = new List<double>();
            List<float> fl = new List<float>();

            if ((MiscCoreFuncts.CharCount(input, '{') < 1) || (MiscCoreFuncts.CharCount(input, '{') > 1)) throw new CSException("Invalid input format");
            if ((MiscCoreFuncts.CharCount(input, '}') < 1) || (MiscCoreFuncts.CharCount(input, '}') > 1)) throw new CSException("Invalid input format");
            StringBuilder s = new StringBuilder(input);
            s = s.Replace("{", "");
            s = s.Replace("}", "");
            string[] items = s.ToString().Split(';');

            switch (Program.loaded.Set_mem.StorageMode)
            {
                case SetStorageType.mDouble:
                    foreach (string item in items) db.Add(MiscFuncts.parsestr(item));
                    return new DoubleSet(db);
                case SetStorageType.mFloat:
                    foreach (string item in items) fl.Add((float)MiscFuncts.parsestr(item));
                    return new FloatSet(fl);
                default:
                    foreach (string item in items) fl.Add((float)MiscFuncts.parsestr(item));
                    return new FloatSet(fl);
            }
        }

        public static ASet Analize(Stream In)
        {
            byte[] buff = new byte[4096]; //4kb
            int i, cnt;
            Dictionary<byte, int> dic = new Dictionary<byte, int>();
            List<double> its = new List<double>();
            do
            {
                cnt = In.Read(buff, 0, buff.Length);
                for (i = 0; i < cnt; i++)
                {
                    if (dic.ContainsKey(buff[i])) dic[buff[i]] += 1;
                    else dic.Add(buff[i], 1);
                }
            }
            while (cnt > 0);
            foreach (byte key in dic.Keys) its.Add(dic[key]);
            return SetFuncts.CreateSet(its);
        }

        public static ASet Filter(ASet input, string formula)
        {
            List<double> its = new List<double>();
            ReversePolishNotation rpn = new ReversePolishNotation();
            rpn.Parse(formula);
            for (int i=0; i<input.Count; i++)
            {
                Program.loaded.Mem["$x"] = input[i];
                if (rpn.Evaluate() > 0) its.Add(input[i]);
            }
            return SetFuncts.CreateSet(its);
        }

        public static void ApendToSet(string its, ASet dest)
        {
            string[] ita = its.Split(';');
            foreach (string it in ita) dest.AddItem(MiscFuncts.parsestr(it));
        }

        public static ASet CreateSet(List<double> list)
        {
            ASet ret;
            switch (Program.loaded.Set_mem.StorageMode)
            {
                case SetStorageType.mDouble:
                    return new DoubleSet(list);
                case SetStorageType.mFloat:
                    ret = new FloatSet(list.Count);
                    break;
                default:
                    ret = new FloatSet(list.Count);
                    break;
            }
            for (int i = 0; i < list.Count; i++)
            {
                ret[i] = list[i];
            }
            return ret;
        }

        public static ASet CreateSet(int count)
        {
            switch (Program.loaded.Set_mem.StorageMode)
            {
                case SetStorageType.mDouble:
                    return new DoubleSet(count);
                case SetStorageType.mFloat:
                    return new FloatSet(count);
                default:
                    return new FloatSet(count);
            }
        }

        public static ASet AplyOperation(ASet i1, ASet i2, string operation)
        {
            switch (Program.loaded.Set_mem.StorageMode)
            {
                case SetStorageType.mDouble:
                    if (operation == "+") return (DoubleSet)i1 + (DoubleSet)i2;
                    else if (operation == "*") return (DoubleSet)i1 * (DoubleSet)i2;
                    else if (operation == "/") return (DoubleSet)i1 / (DoubleSet)i2;
                    else throw new CSException("Unsuported operation: "+operation);
                case SetStorageType.mFloat:
                    if (operation == "+") return (FloatSet)i1 + (FloatSet)i2;
                    else if (operation == "*") return (FloatSet)i1 * (FloatSet)i2;
                    else if (operation == "/") return (FloatSet)i1 / (FloatSet)i2;
                    else throw new CSException("Unsuported operation: " + operation);
                default:
                    if (operation == "+") return (FloatSet)i1 + (FloatSet)i2;
                    else if (operation == "*") return (FloatSet)i1 * (FloatSet)i2;
                    else if (operation == "/") return (FloatSet)i1 / (FloatSet)i2;
                    else throw new CSException("Unsuported operation: " + operation);
            }
        }
    }
}
